package com.xcc.httpUtils;

import com.xcc.httpUtils.callback.BaseHttpCallBack;
import com.xcc.httpUtils.request.RequestCall;
import com.xcc.httpUtils.ssl.TrustAllCerts;
import com.xcc.httpUtils.utils.StringUtils;
import com.xcc.httpUtils.builder.*;
import okhttp3.*;

import javax.net.ssl.*;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by Carman on 2017/7/7.
 * OKHttp 工具使用类
 */
public class HttpUtils {

    // cookie
    private final static HashMap<String, List<Cookie>> cookieStore = new HashMap<>();
    private volatile static HttpClientBuild mBuilder;
    private volatile static HttpUtils mInstance; //单例
    private OkHttpClient mOkHttpClient;  //okHttp 请求类


    public HttpUtils(OkHttpClient okHttpClient) {
        if (okHttpClient == null) {
            mOkHttpClient = new OkHttpClient();
        } else {
            mOkHttpClient = okHttpClient;
        }
    }

    /**
     * 初始化 OKHttpClient
     *
     * @param okHttpClient OkHttpClient
     * @return 当前对象 HttpUtils
     */
    public final static HttpUtils initClient(OkHttpClient okHttpClient) {
        if (mInstance == null) {
            synchronized (HttpUtils.class) {
                if (mInstance == null) {
                    mInstance = new HttpUtils(okHttpClient);
                }
            }
        }
        return mInstance;
    }

    /**
     * 初始化带 cookies 的 HttpClient
     * {@link HttpUtils#build() 通过 HttpClientBuild 初始化 cookie}
     */
    @Deprecated
    public final static void initClientCookie() {
        OkHttpClient client = new OkHttpClient.Builder()
                .cookieJar(new CookieJar() {
                    @Override
                    public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
                        List<Cookie> cookiesList = cookieStore.get(url.host());
//                                    System.out.println("保存: " + cookieStore.keySet());
                        if (cookiesList != null) {
                            cookieStore.remove(url.host());
                        }
                        //再重新添加
                        if (cookiesList != null && cookiesList.size() > 0) {
                        }
                        cookieStore.put(url.host(), cookies);
                    }

                    @Override
                    public List<Cookie> loadForRequest(HttpUrl url) {
                        List<Cookie> cookiesList = cookieStore.get(url.host());
//                                    System.out.println("加载: " + cookieStore.keySet());
                        if (cookiesList != null && cookiesList.size() > 0) {
                        }
                        return cookiesList != null ? cookiesList : new ArrayList<Cookie>();
                    }
                }).build();
        initClient(client);
    }

    public final HttpUtils initCookie() {
        OkHttpClient client = new OkHttpClient.Builder()
                .cookieJar(new CookieJar() {
                    @Override
                    public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
                        List<Cookie> cookiesList = cookieStore.get(url.host());
//                                    System.out.println("保存: " + cookieStore.keySet());
                        if (cookiesList != null) {
                            cookieStore.remove(url.host());
                        }
                        //再重新添加
                        if (cookiesList != null && cookiesList.size() > 0) {
                        }
                        cookieStore.put(url.host(), cookies);
                    }

                    @Override
                    public List<Cookie> loadForRequest(HttpUrl url) {
                        List<Cookie> cookiesList = cookieStore.get(url.host());
//                                    System.out.println("加载: " + cookieStore.keySet());
                        if (cookiesList != null && cookiesList.size() > 0) {
                        }
                        return cookiesList != null ? cookiesList : new ArrayList<Cookie>();
                    }
                }).build();
        initClient(client);
        return this;
    }

    public final HttpUtils ssl() throws NoSuchAlgorithmException, KeyManagementException {
        final TrustManager[] trustAllCerts = new TrustManager[]{new TrustAllCerts()};
        final SSLContext sslContext = SSLContext.getInstance("SSL");
        sslContext.init(null, trustAllCerts, new SecureRandom());
        final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        builder.sslSocketFactory(sslSocketFactory);
        builder.hostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        });
        return this;
    }

    public final static HttpClientBuild build() {
        if (null == mBuilder) {
            synchronized (HttpUtils.class) {
                if (null == mBuilder) {
                    OkHttpClient.Builder builder = new OkHttpClient.Builder();
                    mBuilder = new HttpClientBuild(builder);
                }
            }
        }
        return mBuilder;
    }

    /**
     * 获取 cookie
     *
     * @return
     */
    public final static Map getCookie() {
        return cookieStore;
    }

    /**
     * 实例化 HttpUtils 类
     *
     * @return HttpUtils 对象
     */
    public static HttpUtils getInstance() {
        return initClient(null);
    }

    /**
     * 获取 OkHttpClient
     *
     * @return OkHttpClient 对象
     */
    public OkHttpClient getOkHttpClient() {
        return mOkHttpClient;
    }

    /**
     * 异步请求
     *
     * @param requestCall RequestCall 对象
     * @param callback    回调
     */
    public void enqueue(final RequestCall requestCall, BaseHttpCallBack callback) {
        if (callback == null) {
            callback = BaseHttpCallBack.DEFAULT_CALLBACK;
        }
        final BaseHttpCallBack finalCallback = callback;

        requestCall.getCall().enqueue(new okhttp3.Callback() {
            @Override
            public void onFailure(Call call, final IOException e) {
                try {
                    finalCallback.requestError(call, e);
                } catch (NullPointerException e1) {
                    System.err.println("HttpUtils NullPointerException Error");
                }
            }

            @Override
            public void onResponse(final Call call, final Response response) {
                callBack(call, response, finalCallback);
            }
        });
    }

    /**
     * 创建一个 webSocket 链接
     *
     * @param request
     * @param webSocketListener
     */
    public void newWebSocket(final Request request, WebSocketListener webSocketListener) {
        if (null == webSocketListener) {
            throw new NullPointerException("param webSocketListener is null");
        }
        if (null == request) {
            throw new NullPointerException("param request is null");
        }
        getOkHttpClient().newWebSocket(request, webSocketListener);
    }

    /**
     * 同步请求
     *
     * @param requestCall RequestCall 对象
     * @return 请求返回的结果集
     * @throws IOException 请求异常
     */
    public Response execute(final RequestCall requestCall) throws IOException {
        return requestCall.getCall().execute();
    }

    /**
     * 同步方法执行，执行回调请求
     *
     * @param requestCall
     * @param callback
     */
    public void executeCallBack(final RequestCall requestCall, BaseHttpCallBack callback) {
        Response response = null;
        if (callback == null) {
            callback = BaseHttpCallBack.DEFAULT_CALLBACK;
        }
        final BaseHttpCallBack finalCallback = callback;
        try {
            response = requestCall.getCall().execute();
        } catch (Exception e) {
            e.printStackTrace();
            try {
                callback.requestError(requestCall.getCall(), e);
            } catch (NullPointerException e1) {
                System.err.println("HttpUtils NullPointerException Error");
            }

            return;
        }
        callBack(requestCall.getCall(), response, finalCallback);
    }

    /**
     * 请求回调
     *
     * @param call
     * @param response
     * @param finalCallback
     */
    private void callBack(Call call, Response response, BaseHttpCallBack finalCallback) {
        try {
            if (call.isCanceled()) {
                //连接失败
                finalCallback.requestError(call, new IOException("Canceled!"));
                return;
            }
            finalCallback.netWorkRequestSuccess(call, response);
        } catch (NullPointerException e) {
            //异常
//            finalCallback.requestError(call, e);
            System.err.println("HttpUtils NullPointerException Error");
            return;
        }
        if (response.body() != null) {
            response.body().close();
        }
    }

    /**
     * 取消请求
     *
     * @param tag 标记
     */
    public void cancelTag(Object tag) {
        for (Call call : mOkHttpClient.dispatcher().queuedCalls()) {
            if (tag.equals(call.request().tag())) {
                call.cancel();
            }
        }
        for (Call call : mOkHttpClient.dispatcher().runningCalls()) {
            if (tag.equals(call.request().tag())) {
                call.cancel();
            }
        }
    }

    /**
     * post 请求
     *
     * @return PostBuilder post 请求数据配置类
     */
    public static PostBuilder post(String url) {
        return new PostBuilder(url);
    }

    /**
     * get 请求
     *
     * @return PostBuilder get 请求数据配置类
     */
    public static GetBuilder get(String url) {
        return new GetBuilder(url);
    }

    public static DeleteBuilder delete(String url) {
        return new DeleteBuilder(url);
    }

    public static PatchBuilder patch(String url) {
        return new PatchBuilder(url);
    }

    public static PutBuilder put(String url) {
        return new PutBuilder(url);
    }


    /**
     * get 方式下载文件
     *
     * @return PostBuilder get 请求数据配置类
     */
    public static GetDownFileBuilder downFile(String url) {
        return new GetDownFileBuilder(url);
    }

    /**
     * 上传文件及表单参数
     *
     * @param url 地址
     * @return PostFormBuilder
     */
    public static PostFormBuilder postForm(String url) {
        return new PostFormBuilder(url);
    }

    /**
     * webSocket 请求
     *
     * @param url
     * @return
     */
    public static WebSocketBuilder webSocket(String url) {
//        System.out.println("是否为空: " + StringUtils.isEmpty(url));
//        System.out.println("是否已前缀开头: " + (url.startsWith("ws://") || url.startsWith("wss://")));
        if ((!StringUtils.isEmpty(url)) && ((url.startsWith("ws://") || url.startsWith("wss://")))) {
            return new WebSocketBuilder(url);
        }
        throw new IllegalArgumentException("Illegal parameters url");
    }
}

